import builtins
import re,os
import sys
import math
from enum import Enum, auto
from typing import Any, Dict, List, Optional, Union, Tuple

class NovaError(Exception):
    def __init__(self, message, line=None, column=None):
        self.message = message
        self.line = line
        self.column = column
        super().__init__(f"Line {line}:{column} - {message}")

class TokenType(Enum):
    COLON = auto()
    NUMBER = auto()
    STRING = auto()
    BOOL = auto()
    NIL = auto()
    ASSIGN = auto()
    RIGHT_ARROW = auto()
    LEFT_ARROW = auto()
    DOUBLE_LEFT_ARROW = auto()
    DOUBLE_RIGHT_ARROW = auto()
    PLUS = auto()
    MINUS = auto()
    PERCENT = auto()
    ADD = auto()
    SUBTRACT = auto()
    MULTIPLY = auto()
    DIVIDE = auto()
    FLOOR_DIV = auto()
    POWER = auto()
    MODULO = auto()
    EQUAL = auto()
    NOT_EQUAL = auto()
    GREATER = auto()
    LESS = auto()
    DIAMOND = auto()
    LESS_EQUAL = auto()
    GREATER_EQUAL = auto()
    STRICT_EQUAL = auto()
    STRICT_NOT_EQUAL = auto()
    IN = auto()
    NOT_IN = auto()
    IS = auto()
    NOT_IS = auto()
    MATCH = auto()
    NOT_MATCH = auto()
    AND = auto()
    OR = auto()
    XOR = auto()
    NOT = auto()
    DOT = auto()
    COMMA = auto()
    LPAREN = auto()
    RPAREN = auto()
    LBRACKET = auto()
    RBRACKET = auto()
    LBRACE = auto()
    RBRACE = auto()
    PRINT = auto()
    PRINTF = auto()
    INPUT = auto()
    SCANF = auto()
    CONST = auto()
    REGEX = auto()
    IDENTIFIER = auto()
    NEWLINE = auto()
    EOF = auto()
    SYS = auto()
    EVAL = auto()
    END = auto()
    NOP = auto()
    EXIT = auto()
    COLOR = auto()
    CLS = auto()
    WAIT = auto()
    IF = auto()
    ELIF = auto()
    ELSE = auto()
    UNLESS = auto()
    WHILE = auto()
    UNTIL = auto()
    DO = auto()
    LOOP = auto()
    REP = auto()
    BREAK = auto()
    CONTINUE = auto()
    INDENT = auto()
    DEDENT = auto()
    MATCH_KW = auto()
    WHEN = auto()
    UNDERSCORE = auto()
    SUB = auto()
    TRY = auto()
    EXCEPT = auto()
    FINALLY = auto()
    POS = auto()
    NEG = auto()
    ZRO = auto()
    EXIST = auto()
    FOR = auto()
    SEMICOLON = auto()

class Token:
    def __init__(self, type: TokenType, value: Any = None, line: int = None, column: int = None):
        self.type = type
        self.value = value
        self.line = line
        self.column = column
    
    def __repr__(self):
        return f"Token({self.type}, {self.value}, line={self.line}, col={self.column})"

class Lexer:
    def __init__(self, text: str):
        self.text = text
        self.pos = 0
        self.line = 1
        self.column = 1
        self.current_char = self.text[self.pos] if self.text else None
        self.indent_stack = [0]
        self.pending_dedents = 0
        self.at_line_start = True
    
    def advance(self):
        if self.current_char == '\n':
            self.line += 1
            self.column = 0
            self.at_line_start = True
        self.pos += 1
        self.column += 1
        if self.pos < len(self.text):
            self.current_char = self.text[self.pos]
        else:
            self.current_char = None
    
    def peek(self, n=1):
        peek_pos = self.pos + n
        if peek_pos < len(self.text):
            return self.text[peek_pos]
        return None
    
    def skip_whitespace(self):
        while self.current_char is not None and self.current_char.isspace() and self.current_char != '\n':
            self.advance()
    
    def skip_comment(self):
        while self.current_char is not None and self.current_char != '\n':
            self.advance()
        if self.current_char == '\n':
            self.advance()
    
    def handle_indentation(self):
        indent = 0
        while self.current_char is not None and self.current_char in ' \t':
            if self.current_char == ' ':
                indent += 1
            elif self.current_char == '\t':
                indent += 4
            self.advance()
        
        if self.current_char == '\n' or self.current_char is None:
            return None
        
        current_indent = self.indent_stack[-1]
        if indent > current_indent:
            self.indent_stack.append(indent)
            return Token(TokenType.INDENT, indent, self.line, self.column)
        elif indent < current_indent:
            tokens = []
            while indent < self.indent_stack[-1]:
                self.indent_stack.pop()
                tokens.append(Token(TokenType.DEDENT, self.indent_stack[-1], self.line, self.column))
                if not self.indent_stack:
                    raise Exception(f"Indentation error at line {self.line}")
            return tokens
        return None
    
    def number(self):
        result = ''
        start_line = self.line
        start_column = self.column
        while self.current_char is not None and self.current_char.isdigit():
            result += self.current_char
            self.advance()
        
        if self.current_char == '.':
            result += self.current_char
            self.advance()
            while self.current_char is not None and self.current_char.isdigit():
                result += self.current_char
                self.advance()
        
        return Token(TokenType.NUMBER, float(result), start_line, start_column)
    
    def string(self):
        result = ''
        delimiter = self.current_char
        start_line = self.line
        start_column = self.column
        self.advance()
        
        while self.current_char is not None and self.current_char != delimiter:
            if self.current_char == '\\':
                self.advance()
                if self.current_char == 'n':
                    result += '\n'
                elif self.current_char == 't':
                    result += '\t'
                else:
                    result += self.current_char
            else:
                result += self.current_char
            self.advance()
        
        if self.current_char != delimiter:
            raise Exception(f"Unterminated string at line {self.line}")
        
        self.advance()
        return Token(TokenType.STRING, result, start_line, start_column)
    
    def regex(self):
        result = ''
        start_line = self.line
        start_column = self.column
        self.advance()
        
        while self.current_char is not None and self.current_char != '/':
            if self.current_char == '\\':
                result += self.current_char
                self.advance()
                if self.current_char is not None:
                    result += self.current_char
                    self.advance()
            else:
                result += self.current_char
                self.advance()
        
        if self.current_char != '/':
            raise Exception(f"Unterminated regex at line {self.line}")
        
        self.advance()
        return Token(TokenType.REGEX, result, start_line, start_column)
    
    def identifier(self):
        result = ''
        start_line = self.line
        start_column = self.column
        while self.current_char is not None and (self.current_char.isalnum() or self.current_char == '_'):
            result += self.current_char
            self.advance()
        
        if result == 'true':
            return Token(TokenType.BOOL, True, start_line, start_column)
        elif result == 'false':
            return Token(TokenType.BOOL, False, start_line, start_column)
        elif result == 'nil':
            return Token(TokenType.NIL, None, start_line, start_column)
        elif result == 'print':
            return Token(TokenType.PRINT, None, start_line, start_column)
        elif result == 'printf':
            return Token(TokenType.PRINTF, None, start_line, start_column)
        elif result == 'input':
            return Token(TokenType.INPUT, None, start_line, start_column)
        elif result == 'scanf':
            return Token(TokenType.SCANF, None, start_line, start_column)
        elif result == 'const':
            return Token(TokenType.CONST, None, start_line, start_column)
        elif result == 'and':
            return Token(TokenType.AND, None, start_line, start_column)
        elif result == 'or':
            return Token(TokenType.OR, None, start_line, start_column)
        elif result == 'xor':
            return Token(TokenType.XOR, None, start_line, start_column)
        elif result == 'not':
            start_pos = self.pos
            start_line = self.line
            start_column = self.column
            
            self.skip_whitespace()
            next_word = ''
            while self.current_char is not None and (self.current_char.isalpha() or self.current_char == '_'):
                next_word += self.current_char
                self.advance()
            
            if next_word == 'in':
                return Token(TokenType.NOT_IN, None, start_line, start_column)
            elif next_word == 'is':
                return Token(TokenType.NOT_IS, None, start_line, start_column)
            else:
                self.pos = start_pos
                self.line = start_line
                self.column = start_column
                self.current_char = self.text[self.pos] if self.pos < len(self.text) else None
                return Token(TokenType.NOT, None, start_line, start_column)
        elif result == 'in':
            return Token(TokenType.IN, None, start_line, start_column)
        elif result == 'is':
            return Token(TokenType.IS, None, start_line, start_column)
        elif result == 'sys':
            return Token(TokenType.SYS, None, start_line, start_column)
        elif result == 'eval':
            return Token(TokenType.EVAL, None, start_line, start_column)
        elif result == 'end':
            return Token(TokenType.END, None, start_line, start_column)
        elif result == 'nop':
            return Token(TokenType.NOP, None, start_line, start_column)
        elif result == 'exit':
            return Token(TokenType.EXIT, None, start_line, start_column)
        elif result == 'color':
            return Token(TokenType.COLOR, None, start_line, start_column)
        elif result == 'cls':
            return Token(TokenType.CLS, None, start_line, start_column)
        elif result == 'wait':
            return Token(TokenType.WAIT, None, start_line, start_column)
        elif result == 'if':
            return Token(TokenType.IF, None, start_line, start_column)
        elif result == 'elif':
            return Token(TokenType.ELIF, None, start_line, start_column)
        elif result == 'else':
            return Token(TokenType.ELSE, None, start_line, start_column)
        elif result == 'unless':
            return Token(TokenType.UNLESS, None, start_line, start_column)
        elif result == 'while':
            return Token(TokenType.WHILE, None, start_line, start_column)
        elif result == 'until':
            return Token(TokenType.UNTIL, None, start_line, start_column)
        elif result == 'do':
            return Token(TokenType.DO, None, start_line, start_column)
        elif result == 'loop':
            return Token(TokenType.LOOP, None, start_line, start_column)
        elif result == 'rep':
            return Token(TokenType.REP, None, start_line, start_column)
        elif result == 'break':
            return Token(TokenType.BREAK, None, start_line, start_column)
        elif result == 'continue':
            return Token(TokenType.CONTINUE, None, start_line, start_column)
        elif result == 'match':
            return Token(TokenType.MATCH_KW, None, start_line, start_column)
        elif result == 'when':
            return Token(TokenType.WHEN, None, start_line, start_column)
        elif result == '_':
            return Token(TokenType.UNDERSCORE, None, start_line, start_column)
        elif result == 'try':
            return Token(TokenType.TRY, None, start_line, start_column)
        elif result == 'except':
            return Token(TokenType.EXCEPT, None, start_line, start_column)
        elif result == 'finally':
            return Token(TokenType.FINALLY, None, start_line, start_column)
        elif result == 'sub':
            return Token(TokenType.SUB, result, start_line, start_column)
        elif result == 'pos':
            return Token(TokenType.POS, result, start_line, start_column)
        elif result == 'neg':
            return Token(TokenType.NEG, result, start_line, start_column)
        elif result == 'zro':
            return Token(TokenType.ZRO, result, start_line, start_column)
        elif result == 'exist':
            return Token(TokenType.EXIST, result, start_line, start_column)
        elif result == 'for':
            return Token(TokenType.FOR, None, start_line, start_column)
        else:
            return Token(TokenType.IDENTIFIER, result, start_line, start_column)
    
    def get_next_token(self):
        if self.pending_dedents > 0:
            self.pending_dedents -= 1
            return Token(TokenType.DEDENT, self.indent_stack[-1], self.line, self.column)
        
        while self.current_char is not None:
            if self.at_line_start:
                self.at_line_start = False
                indent_tokens = self.handle_indentation()
                if indent_tokens:
                    if isinstance(indent_tokens, list):
                        self.pending_dedents = len(indent_tokens) - 1
                        return indent_tokens[0]
                    return indent_tokens
                if self.current_char == '\n' or self.current_char is None:
                    continue
            
            if self.current_char.isspace() and self.current_char != '\n':
                self.skip_whitespace()
                continue
            
            if self.current_char == '#':
                self.skip_comment()
                continue
            
            if self.current_char == '\n':
                self.advance()
                self.at_line_start = True
                return Token(TokenType.NEWLINE, None, self.line, self.column)
            
            if self.current_char.isdigit():
                return self.number()
            
            if self.current_char in ('"', "'"):
                return self.string()
            
            if self.current_char == ':':
                start_line = self.line
                start_column = self.column
                self.advance()
                return Token(TokenType.COLON, None, start_line, start_column)

            if self.current_char == '/':
                if self.peek() == '/':
                    self.advance()
                    self.advance()
                    return Token(TokenType.FLOOR_DIV, None, self.line, self.column)
                elif self.peek() == '*':
                    self.advance()
                    self.advance()
                    while self.current_char is not None and not (self.current_char == '*' and self.peek() == '/'):
                        self.advance()
                    if self.current_char is None:
                        raise Exception("Unterminated comment")
                    self.advance()
                    self.advance()
                    continue
                else:
                    return self.regex() if self.peek() not in ('=', '>', '<') else self._get_operator()
            
            if self.current_char.isalpha() or self.current_char == '_':
                return self.identifier()
            
            token = self._get_operator()
            if token:
                return token
            
            char = self.current_char
            start_line = self.line
            start_column = self.column
            self.advance()
            
            if char == '+':
                return Token(TokenType.ADD, None, start_line, start_column)
            elif char == '-':
                return Token(TokenType.SUBTRACT, None, start_line, start_column)
            elif char == '*':
                if self.current_char == '*':
                    self.advance()
                    return Token(TokenType.POWER, None, start_line, start_column)
                return Token(TokenType.MULTIPLY, None, start_line, start_column)
            elif char == '%':
                return Token(TokenType.MODULO, None, start_line, start_column)
            elif char == '.':
                return Token(TokenType.DOT, None, start_line, start_column)
            elif char == ',':
                return Token(TokenType.COMMA, None, start_line, start_column)
            elif char == '(':
                return Token(TokenType.LPAREN, None, start_line, start_column)
            elif char == ')':
                return Token(TokenType.RPAREN, None, start_line, start_column)
            elif char == '[':
                return Token(TokenType.LBRACKET, None, start_line, start_column)
            elif char == ']':
                return Token(TokenType.RBRACKET, None, start_line, start_column)
            elif char == '{':
                return Token(TokenType.LBRACE, None, start_line, start_column)
            elif char == '}':
                return Token(TokenType.RBRACE, None, start_line, start_column)
            elif char == ';':
                return Token(TokenType.SEMICOLON, None, start_line, start_column)
            else:
                raise Exception(f"Unknown character: {char} at line {self.line}")
            
        if self.indent_stack and self.indent_stack[-1] > 0:
            self.indent_stack.pop()
            if self.indent_stack and self.indent_stack[-1] > 0:
                self.pending_dedents = len(self.indent_stack) - 1
                return Token(TokenType.DEDENT, self.indent_stack[-1], self.line, self.column)
        
        return Token(TokenType.EOF, None, self.line, self.column)
    
    def _get_operator(self):
        char = self.current_char
        line = self.line
        column = self.column
        
        if char == '=':
            self.advance()
            if self.current_char == '=':
                self.advance()
                if self.current_char == '=':
                    self.advance()
                    return Token(TokenType.STRICT_EQUAL, None, line, column)
                return Token(TokenType.EQUAL, None, line, column)
            elif self.current_char == '~':
                self.advance()
                return Token(TokenType.MATCH, None, line, column)
            return Token(TokenType.ASSIGN, None, line, column)
        
        elif char == '!':
            self.advance()
            if self.current_char == '=':
                self.advance()
                if self.current_char == '=':
                    self.advance()
                    return Token(TokenType.STRICT_NOT_EQUAL, None, line, column)
                return Token(TokenType.NOT_EQUAL, None, line, column)
            elif self.current_char == '~':
                self.advance()
                return Token(TokenType.NOT_MATCH, None, line, column)
            return Token(TokenType.NOT, None, line, column)
        elif char == '<':
            self.advance()
            if self.current_char == '<' and self.peek() == '-':
                self.advance()
                self.advance()
                return Token(TokenType.DOUBLE_LEFT_ARROW, None, line, column)
            elif self.current_char == '-':
                self.advance()
                return Token(TokenType.LEFT_ARROW, None, line, column)
            elif self.current_char == '>':
                self.advance()
                return Token(TokenType.DIAMOND, None, line, column)
            elif self.current_char == '=':
                self.advance()
                return Token(TokenType.LESS_EQUAL, None, line, column)
            return Token(TokenType.LESS, None, line, column)
        
        elif char == '>':
            self.advance()
            if self.current_char == '>' and self.peek() == '-':
                self.advance()
                self.advance()
                return Token(TokenType.DOUBLE_RIGHT_ARROW, None, line, column)
            elif self.current_char == '=':
                self.advance()
                return Token(TokenType.GREATER_EQUAL, None, line, column)
            return Token(TokenType.GREATER, None, line, column)
        
        elif char == '-':
            self.advance()
            if self.current_char == '>':
                self.advance()
                return Token(TokenType.RIGHT_ARROW, None, line, column)
            return Token(TokenType.SUBTRACT, None, line, column)
        
        return None

class ASTNode:
    pass

class Block(ASTNode):
    def __init__(self, statements: List[ASTNode]):
        self.statements = statements

class BinOp(ASTNode):
    def __init__(self, left: ASTNode, op: Token, right: ASTNode):
        self.left = left
        self.op = op
        self.right = right

class UnaryOp(ASTNode):
    def __init__(self, op: Token, expr: ASTNode):
        self.op = op
        self.expr = expr

class Num(ASTNode):
    def __init__(self, token: Token):
        self.token = token
        self.value = token.value

class Str(ASTNode):
    def __init__(self, token: Token):
        self.token = token
        self.value = token.value

class Bool(ASTNode):
    def __init__(self, token: Token):
        self.token = token
        self.value = token.value

class Nil(ASTNode):
    def __init__(self, token: Token):
        self.token = token
        self.value = token.value

class Var(ASTNode):
    def __init__(self, token: Token):
        self.token = token
        self.value = token.value

class SubCall(ASTNode):
    def __init__(self, token: Token):
        self.token = token
        self.value = token.value

class Assign(ASTNode):
    def __init__(self, left: ASTNode, op: Token, right: ASTNode):
        self.left = left
        self.op = op
        self.right = right

class Print(ASTNode):
    def __init__(self, expr: ASTNode):
        self.expr = expr

class Printf(ASTNode):
    def __init__(self, format_string: ASTNode, args: List[ASTNode] = None):
        self.format_string = format_string
        self.args = args if args else []

class Input(ASTNode):
    def __init__(self, prompt: ASTNode = None):
        self.prompt = prompt

class Scanf(ASTNode):
    def __init__(self, format_string: ASTNode, vars: List[Var]):
        self.format_string = format_string
        self.vars = vars

class ConstDecl(ASTNode):
    def __init__(self, name: Token, value: ASTNode):
        self.name = name
        self.value = value

class Sys(ASTNode):
    def __init__(self, command: ASTNode):
        self.command = command

class Eval(ASTNode):
    def __init__(self, code: ASTNode):
        self.code = code

class End(ASTNode):
    pass

class Nop(ASTNode):
    pass

class Exit(ASTNode):
    def __init__(self, code: ASTNode = None):
        self.code = code

class Color(ASTNode):
    def __init__(self, color: ASTNode):
        self.color = color

class Cls(ASTNode):
    pass

class Wait(ASTNode):
    def __init__(self, seconds: ASTNode):
        self.seconds = seconds

class If(ASTNode):
    def __init__(self, condition: ASTNode, then_branch: ASTNode, else_branch: ASTNode = None, elif_branches: List[Tuple[ASTNode, ASTNode]] = None):
        self.condition = condition
        self.then_branch = then_branch
        self.else_branch = else_branch
        self.elif_branches = elif_branches if elif_branches else []

class Unless(ASTNode):
    def __init__(self, condition: ASTNode, then_branch: ASTNode, else_branch: ASTNode = None):
        self.condition = condition
        self.then_branch = then_branch
        self.else_branch = else_branch

class While(ASTNode):
    def __init__(self, condition: ASTNode, body: ASTNode):
        self.condition = condition
        self.body = body

class Until(ASTNode):
    def __init__(self, condition: ASTNode, body: ASTNode):
        self.condition = condition
        self.body = body

class DoWhile(ASTNode):
    def __init__(self, condition: ASTNode, body: ASTNode):
        self.condition = condition
        self.body = body

class DoUntil(ASTNode):
    def __init__(self, condition: ASTNode, body: ASTNode):
        self.condition = condition
        self.body = body

class Loop(ASTNode):
    def __init__(self, body: ASTNode):
        self.body = body

class Rep(ASTNode):
    def __init__(self, count: ASTNode, body: ASTNode):
        self.count = count
        self.body = body

class Break(ASTNode):
    pass

class Continue(ASTNode):
    pass

class MatchCase(ASTNode):
    def __init__(self, pattern: ASTNode, body: ASTNode):
        self.pattern = pattern
        self.body = body

class Match(ASTNode):
    def __init__(self, expr: ASTNode, cases: List[MatchCase]):
        self.expr = expr
        self.cases = cases

class WhenCase(ASTNode):
    def __init__(self, condition: ASTNode, body: ASTNode):
        self.condition = condition
        self.body = body

class When(ASTNode):
    def __init__(self, expr: Optional[ASTNode], cases: List[WhenCase], else_case: Optional[ASTNode] = None):
        self.expr = expr
        self.cases = cases
        self.else_case = else_case

class SubDefinition(ASTNode):
    def __init__(self, name: Token, body: Block):
        self.name = name
        self.body = body

class Try(ASTNode):
    def __init__(self,try_branch: ASTNode, except_branch: ASTNode, finally_branch: ASTNode):
        self.try_branch = try_branch
        self.except_branch = except_branch
        self.finally_branch = finally_branch

class ConditionNode(ASTNode):
    """基础条件节点"""
    def __init__(self, expr: ASTNode):
        self.expr = expr

class PosCondition(ConditionNode):
    """正数判断节点"""
    pass

class NegCondition(ConditionNode):
    """负数判断节点"""
    pass

class ZroCondition(ConditionNode):
    """零判断节点"""
    pass

class ExistCondition(ConditionNode):
    """文件存在判断节点"""
    pass

class BuiltinCall(ASTNode):
    def __init__(self, token: Token, args: List[ASTNode] = None):
        self.token = token
        self.func_name = token.value
        self.args = args if args else []

class ForIn(ASTNode):
    def __init__(self, var: Token, iterable: ASTNode, body: ASTNode):
        self.var = var
        self.iterable = iterable
        self.body = body

class ForRange(ASTNode):
    def __init__(self, init: Optional[ASTNode], condition: Optional[ASTNode], 
                 update: Optional[ASTNode], body: ASTNode):
        self.init = init
        self.condition = condition
        self.update = update
        self.body = body

class Parser:
    def __init__(self, lexer: Lexer):
        self.lexer = lexer
        self.current_token = self.lexer.get_next_token()
    
    def error(self, message: str):
        raise Exception(f"Parser error at line {self.current_token.line}:{self.current_token.column}: {message}")
    
    def eat(self, token_type: TokenType):
        if self.current_token.type == token_type:
            self.current_token = self.lexer.get_next_token()
        else:
            self.error(f"Expected {token_type}, got {self.current_token.type}")
    
    def parse_block(self) -> Block:
        self.eat(TokenType.NEWLINE)
        self.eat(TokenType.INDENT)
        
        statements = []
        while self.current_token.type != TokenType.DEDENT and self.current_token.type != TokenType.EOF:
            if self.current_token.type == TokenType.NEWLINE:
                self.eat(TokenType.NEWLINE)
                continue
            
            statement = self.statement()
            statements.append(statement)
            
            if self.current_token.type != TokenType.DEDENT and self.current_token.type != TokenType.EOF:
                self.eat(TokenType.NEWLINE)
        
        if self.current_token.type == TokenType.DEDENT:
            self.eat(TokenType.DEDENT)
        
        return Block(statements)
    
    def statement(self):
        token = self.current_token
        
        if token.type == TokenType.IF:
            return self.if_statement()
        elif token.type == TokenType.UNLESS:
            return self.unless_statement()
        elif token.type == TokenType.WHILE:
            return self.while_statement()
        elif token.type == TokenType.UNTIL:
            return self.until_statement()
        elif token.type == TokenType.DO:
            return self.do_statement()
        elif token.type == TokenType.LOOP:
            return self.loop_statement()
        elif token.type == TokenType.REP:
            return self.rep_statement()
        elif token.type == TokenType.BREAK:
            return self.break_statement()
        elif token.type == TokenType.CONTINUE:
            return self.continue_statement()
        elif token.type == TokenType.MATCH_KW:
            return self.match_statement()
        elif token.type == TokenType.WHEN:
            return self.when_statement()
        elif token.type == TokenType.IDENTIFIER and token.value == 'sub':
            return self.sub_definition()
        else:
            return self.expr()
    
    def sub_definition(self):
        self.eat(TokenType.IDENTIFIER)  # Eat 'sub'
        
        if self.current_token.type != TokenType.IDENTIFIER:
            self.error("Expected identifier after 'sub'")
        name = self.current_token
        self.eat(TokenType.IDENTIFIER)
        
        self.eat(TokenType.COLON)
        
        if self.current_token.type == TokenType.NEWLINE:
            body = self.parse_block()
        else:
            body = Block([self.statement()])
        
        return SubDefinition(name, body)
    
    def when_statement(self):
        self.eat(TokenType.WHEN)
        
        expr = None
        if self.current_token.type != TokenType.COLON:
            expr = self.expr()
        self.eat(TokenType.COLON)
        
        self.eat(TokenType.NEWLINE)
        self.eat(TokenType.INDENT)
        
        cases = []
        else_case = None
        
        while self.current_token.type != TokenType.DEDENT and self.current_token.type != TokenType.EOF:
            if self.current_token.type == TokenType.ELSE:
                self.eat(TokenType.ELSE)
                self.eat(TokenType.COLON)
                if self.current_token.type == TokenType.NEWLINE:
                    else_case = self.parse_block()
                else:
                    else_case = self.statement()
                break
            
            condition = self.expr()
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                body = self.parse_block()
            else:
                body = self.statement()
            
            cases.append(WhenCase(condition, body))
        
        self.eat(TokenType.DEDENT)
        return When(expr, cases, else_case)
    
    def match_statement(self):
        self.eat(TokenType.MATCH_KW)
        expr = self.expr()
        self.eat(TokenType.COLON)
        self.eat(TokenType.NEWLINE)
        self.eat(TokenType.INDENT)
        
        cases = []
        while self.current_token.type != TokenType.DEDENT and self.current_token.type != TokenType.EOF:
            if self.current_token.type == TokenType.UNDERSCORE:
                pattern = None
                self.eat(TokenType.UNDERSCORE)
            else:
                pattern = self.expr()
            
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                body = self.parse_block()
            else:
                body = self.statement()
            
            cases.append(MatchCase(pattern, body))
        
        self.eat(TokenType.DEDENT)
        return Match(expr, cases)
    
    def if_statement(self):
        self.eat(TokenType.IF)
        condition = self.expr()
        self.eat(TokenType.COLON)
        
        if self.current_token.type == TokenType.NEWLINE:
            then_branch = self.parse_block()
        else:
            then_branch = self.statement()
        
        elif_branches = []
        while self.current_token.type == TokenType.ELIF:
            self.eat(TokenType.ELIF)
            elif_condition = self.expr()
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                elif_branch = self.parse_block()
            else:
                elif_branch = self.statement()
            
            elif_branches.append((elif_condition, elif_branch))
        
        else_branch = None
        if self.current_token.type == TokenType.ELSE:
            self.eat(TokenType.ELSE)
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                else_branch = self.parse_block()
            else:
                else_branch = self.statement()
        
        return If(condition, then_branch, else_branch, elif_branches)
    
    def unless_statement(self):
        self.eat(TokenType.UNLESS)
        condition = self.expr()
        self.eat(TokenType.COLON)
        
        if self.current_token.type == TokenType.NEWLINE:
            then_branch = self.parse_block()
        else:
            then_branch = self.statement()
        
        else_branch = None
        if self.current_token.type == TokenType.ELSE:
            self.eat(TokenType.ELSE)
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                else_branch = self.parse_block()
            else:
                else_branch = self.statement()
        
        return Unless(condition, then_branch, else_branch)
    
    def while_statement(self):
        self.eat(TokenType.WHILE)
        condition = self.expr()
        self.eat(TokenType.COLON)
        
        if self.current_token.type == TokenType.NEWLINE:
            body = self.parse_block()
        else:
            body = self.statement()
        
        return While(condition, body)
    
    def until_statement(self):
        self.eat(TokenType.UNTIL)
        condition = self.expr()
        self.eat(TokenType.COLON)
        
        if self.current_token.type == TokenType.NEWLINE:
            body = self.parse_block()
        else:
            body = self.statement()
        
        return Until(condition, body)
        
    def do_statement(self):
        self.eat(TokenType.DO)
        
        if self.current_token.type == TokenType.WHILE:
            self.eat(TokenType.WHILE)
            condition = self.expr()
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                body = self.parse_block()
            else:
                body = self.statement()
            
            return DoWhile(condition, body)
        elif self.current_token.type == TokenType.UNTIL:
            self.eat(TokenType.UNTIL)
            condition = self.expr()
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                body = self.parse_block()
            else:
                body = self.statement()
            
            return DoUntil(condition, body)
    
    def loop_statement(self):
        self.eat(TokenType.LOOP)
        self.eat(TokenType.COLON)
        
        if self.current_token.type == TokenType.NEWLINE:
            body = self.parse_block()
        else:
            body = self.statement()
        
        return Loop(body)
    
    def try_statement(self):
        self.eat(TokenType.TRY)
        self.eat(TokenType.COLON)
        try_block = self.parse_block() if self.current_token.type == TokenType.NEWLINE else self.statement()

        self.eat(TokenType.EXCEPT)
        self.eat(TokenType.COLON)
        except_block = self.parse_block() if self.current_token.type == TokenType.NEWLINE else self.statement()
        
        self.eat(TokenType.FINALLY)
        self.eat(TokenType.COLON)
        finally_block = self.parse_block() if self.current_token.type == TokenType.NEWLINE else self.statement()
        
        return Try(try_block, except_block, finally_block)

class Parser:
    builtin_functions = ('sin','cos','tan','asin','acos','atan','log','exp','sqrt','abs','comp','path','max','min')
    def __init__(self, lexer: Lexer):
        self.lexer = lexer
        self.current_token = self.lexer.get_next_token()
    
    def peek(self, n=1):
        """查看前n个token而不消耗当前token"""
        # 保存当前状态
        current_pos = self.lexer.pos
        current_line = self.lexer.line
        current_column = self.lexer.column
        current_char = self.lexer.current_char
        current_token = self.current_token
        
        # 获取前n个token
        tokens = []
        for _ in range(n):
            token = self.lexer.get_next_token()
            if token.type == TokenType.EOF:
                break
            tokens.append(token)
        
        # 恢复状态
        self.lexer.pos = current_pos
        self.lexer.line = current_line
        self.lexer.column = current_column
        self.lexer.current_char = current_char
        self.current_token = current_token
        
        return tokens[0] if tokens else None
    def error(self, message: str):
        raise Exception(f"Parser error at line {self.current_token.line}:{self.current_token.column}: {message}")
    
    def eat(self, token_type: TokenType):
        if self.current_token.type == token_type:
            self.current_token = self.lexer.get_next_token()
        else:
            self.error(f"Expected {token_type}, got {self.current_token.type}")
    
    def parse_block(self) -> Block:
        self.eat(TokenType.NEWLINE)
        self.eat(TokenType.INDENT)
        
        statements = []
        while self.current_token.type != TokenType.DEDENT and self.current_token.type != TokenType.EOF:
            if self.current_token.type == TokenType.NEWLINE:
                self.eat(TokenType.NEWLINE)
                continue
            
            statement = self.statement()
            statements.append(statement)
            
            if self.current_token.type != TokenType.DEDENT and self.current_token.type != TokenType.EOF:
                self.eat(TokenType.NEWLINE)
        
        if self.current_token.type == TokenType.DEDENT:
            self.eat(TokenType.DEDENT)
        
        return Block(statements)
    
    def statement(self):
        token = self.current_token
        
        if token.type == TokenType.IF:
            return self.if_statement()
        elif token.type == TokenType.UNLESS:
            return self.unless_statement()
        elif token.type == TokenType.WHILE:
            return self.while_statement()
        elif token.type == TokenType.UNTIL:
            return self.until_statement()
        elif token.type == TokenType.DO:
            return self.do_statement()
        elif token.type == TokenType.LOOP:
            return self.loop_statement()
        elif token.type == TokenType.REP:
            return self.rep_statement()
        elif token.type == TokenType.BREAK:
            return self.break_statement()
        elif token.type == TokenType.CONTINUE:
            return self.continue_statement()
        elif token.type == TokenType.MATCH_KW:
            return self.match_statement()
        elif token.type == TokenType.WHEN:
            return self.when_statement()
        elif token.type == TokenType.TRY:
            return self.try_statement()
        elif token.type == TokenType.FOR:
            return self.for_statement()
        elif token.type == TokenType.IDENTIFIER and token.value == 'sub':
            return self.sub_definition()
        else:
            return self.expr()
    
    def sub_definition(self):
        self.eat(TokenType.IDENTIFIER)  # Eat 'sub'
        
        if self.current_token.type != TokenType.IDENTIFIER:
            self.error("Expected identifier after 'sub'")
        name = self.current_token
        self.eat(TokenType.IDENTIFIER)
        
        self.eat(TokenType.COLON)
        
        if self.current_token.type == TokenType.NEWLINE:
            body = self.parse_block()
        else:
            body = Block([self.statement()])
        
        return SubDefinition(name, body)
    
    def for_statement(self):
        self.eat(TokenType.FOR)
        
        # 检查是否是for-in循环（标识符后跟IN关键字）
        if (self.current_token.type == TokenType.IDENTIFIER and 
            self.peek() and self.peek().type == TokenType.IN):
            var_token = self.current_token
            self.eat(TokenType.IDENTIFIER)
            self.eat(TokenType.IN)
            iterable = self.expr()
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                body = self.parse_block()
            else:
                body = self.statement()
                
            return ForIn(var_token, iterable, body)
        
        # 否则解析为传统for循环
        # 解析初始化部分（可以是赋值表达式或普通表达式）
        init = None
        if self.current_token.type != TokenType.SEMICOLON:
            init = self.expr()
        self.eat(TokenType.SEMICOLON)
        
        # 解析条件部分
        condition = None
        if self.current_token.type != TokenType.SEMICOLON:
            condition = self.expr()
        self.eat(TokenType.SEMICOLON)
        
        # 解析更新部分
        update = None
        if self.current_token.type != TokenType.COLON:
            update = self.expr()
        self.eat(TokenType.COLON)
        
        # 解析循环体
        if self.current_token.type == TokenType.NEWLINE:
            body = self.parse_block()
        else:
            body = self.statement()
            
        return ForRange(init, condition, update, body)

    def when_statement(self):
        self.eat(TokenType.WHEN)
        
        expr = None
        if self.current_token.type != TokenType.COLON:
            expr = self.expr()
        self.eat(TokenType.COLON)
        
        self.eat(TokenType.NEWLINE)
        self.eat(TokenType.INDENT)
        
        cases = []
        else_case = None
        
        while self.current_token.type != TokenType.DEDENT and self.current_token.type != TokenType.EOF:
            if self.current_token.type == TokenType.ELSE:
                self.eat(TokenType.ELSE)
                self.eat(TokenType.COLON)
                if self.current_token.type == TokenType.NEWLINE:
                    else_case = self.parse_block()
                else:
                    else_case = self.statement()
                break
            
            condition = self.expr()
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                body = self.parse_block()
            else:
                body = self.statement()
            
            cases.append(WhenCase(condition, body))
        
        self.eat(TokenType.DEDENT)
        return When(expr, cases, else_case)
    
    def match_statement(self):
        self.eat(TokenType.MATCH_KW)
        expr = self.expr()
        self.eat(TokenType.COLON)
        self.eat(TokenType.NEWLINE)
        self.eat(TokenType.INDENT)
        
        cases = []
        while self.current_token.type != TokenType.DEDENT and self.current_token.type != TokenType.EOF:
            if self.current_token.type == TokenType.UNDERSCORE:
                pattern = None
                self.eat(TokenType.UNDERSCORE)
            else:
                pattern = self.expr()
            
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                body = self.parse_block()
            else:
                body = self.statement()
            
            cases.append(MatchCase(pattern, body))
        
        self.eat(TokenType.DEDENT)
        return Match(expr, cases)
    
    def if_statement(self):
        self.eat(TokenType.IF)
        
        # 解析条件（支持新条件类型）
        if self.current_token.type == TokenType.POS:
            self.eat(TokenType.POS)
            condition = PosCondition(self.expr())
        elif self.current_token.type == TokenType.NEG:
            self.eat(TokenType.NEG)
            condition = NegCondition(self.expr())
        elif self.current_token.type == TokenType.ZRO:
            self.eat(TokenType.ZRO)
            condition = ZroCondition(self.expr())
        elif self.current_token.type == TokenType.EXIST:
            self.eat(TokenType.EXIST)
            condition = ExistCondition(self.expr())
        else:
            condition = self.expr()  # 普通条件表达式
        
        self.eat(TokenType.COLON)
        
        # 解析then分支
        if self.current_token.type == TokenType.NEWLINE:
            then_branch = self.parse_block()
        else:
            then_branch = self.statement()
        
        # 解析elif分支（同样支持新条件类型）
        elif_branches = []
        while self.current_token.type == TokenType.ELIF:
            self.eat(TokenType.ELIF)
            
            if self.current_token.type == TokenType.POS:
                self.eat(TokenType.POS)
                elif_condition = PosCondition(self.expr())
            elif self.current_token.type == TokenType.NEG:
                self.eat(TokenType.NEG)
                elif_condition = NegCondition(self.expr())
            elif self.current_token.type == TokenType.ZRO:
                self.eat(TokenType.ZRO)
                elif_condition = ZroCondition(self.expr())
            elif self.current_token.type == TokenType.EXIST:
                self.eat(TokenType.EXIST)
                elif_condition = ExistCondition(self.expr())
            else:
                elif_condition = self.expr()
            
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                elif_branch = self.parse_block()
            else:
                elif_branch = self.statement()
            
            elif_branches.append((elif_condition, elif_branch))
        
        # 解析else分支
        else_branch = None
        if self.current_token.type == TokenType.ELSE:
            self.eat(TokenType.ELSE)
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                else_branch = self.parse_block()
            else:
                else_branch = self.statement()
        
        return If(condition, then_branch, else_branch, elif_branches)
    
    def unless_statement(self):
        self.eat(TokenType.UNLESS)
        condition = self.expr()
        self.eat(TokenType.COLON)
        
        if self.current_token.type == TokenType.NEWLINE:
            then_branch = self.parse_block()
        else:
            then_branch = self.statement()
        
        else_branch = None
        if self.current_token.type == TokenType.ELSE:
            self.eat(TokenType.ELSE)
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                else_branch = self.parse_block()
            else:
                else_branch = self.statement()
        
        return Unless(condition, then_branch, else_branch)
    
    def while_statement(self):
        self.eat(TokenType.WHILE)
        condition = self.expr()
        self.eat(TokenType.COLON)
        
        if self.current_token.type == TokenType.NEWLINE:
            body = self.parse_block()
        else:
            body = self.statement()
        
        return While(condition, body)
    
    def until_statement(self):
        self.eat(TokenType.UNTIL)
        condition = self.expr()
        self.eat(TokenType.COLON)
        
        if self.current_token.type == TokenType.NEWLINE:
            body = self.parse_block()
        else:
            body = self.statement()
        
        return Until(condition, body)
        
    def do_statement(self):
        self.eat(TokenType.DO)
        
        if self.current_token.type == TokenType.WHILE:
            self.eat(TokenType.WHILE)
            condition = self.expr()
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                body = self.parse_block()
            else:
                body = self.statement()
            
            return DoWhile(condition, body)
        elif self.current_token.type == TokenType.UNTIL:
            self.eat(TokenType.UNTIL)
            condition = self.expr()
            self.eat(TokenType.COLON)
            
            if self.current_token.type == TokenType.NEWLINE:
                body = self.parse_block()
            else:
                body = self.statement()
            
            return DoUntil(condition, body)
    
    def loop_statement(self):
        self.eat(TokenType.LOOP)
        self.eat(TokenType.COLON)
        
        if self.current_token.type == TokenType.NEWLINE:
            body = self.parse_block()
        else:
            body = self.statement()
        
        return Loop(body)
    
    def try_statement(self):
        self.eat(TokenType.TRY)
        self.eat(TokenType.COLON)
        
        if self.current_token.type == TokenType.NEWLINE:
            try_branch = self.parse_block()
        else:
            try_branch = self.statement()
        
        self.eat(TokenType.EXCEPT)
        self.eat(TokenType.COLON)
        
        if self.current_token.type == TokenType.NEWLINE:
            except_branch = self.parse_block()
        else:
            except_branch = self.statement()
        
        self.eat(TokenType.FINALLY)
        self.eat(TokenType.COLON)
        if self.current_token.type == TokenType.NEWLINE:
            finally_branch = self.parse_block()
        else:
            finally_branch = self.statement()
        
        return Try(try_branch, except_branch, finally_branch)


    def break_statement(self):
        self.eat(TokenType.BREAK)
        return Break()
    
    def continue_statement(self):
        self.eat(TokenType.CONTINUE)
        return Continue()
    
    def factor(self):
        token = self.current_token
        
        if token.type == TokenType.NUMBER:
            self.eat(TokenType.NUMBER)
            return Num(token)
        elif token.type == TokenType.STRING:
            self.eat(TokenType.STRING)
            return Str(token)
        elif token.type == TokenType.BOOL:
            self.eat(TokenType.BOOL)
            return Bool(token)
        elif token.type == TokenType.NIL:
            self.eat(TokenType.NIL)
            return Nil(token)
        elif token.type == TokenType.IDENTIFIER:
            # 检查是否是内置函数调用
            if token.value in self.builtin_functions:
                name_token = token
                self.eat(TokenType.IDENTIFIER)
                args = []
                
                # 检查是否有参数
                if self.current_token.type == TokenType.LPAREN:
                    self.eat(TokenType.LPAREN)
                    
                    # 解析参数列表
                    if self.current_token.type != TokenType.RPAREN:
                        args.append(self.expr())
                        while self.current_token.type == TokenType.COMMA:
                            self.eat(TokenType.COMMA)
                            args.append(self.expr())
                    
                    self.eat(TokenType.RPAREN)
                    return BuiltinCall(name_token, args)
                else:
                    # 没有参数的内置函数调用
                    return BuiltinCall(name_token)
            else:
                # 普通变量
                name_token = token
                self.eat(TokenType.IDENTIFIER)
                return Var(name_token)
        elif token.type == TokenType.LPAREN:
            self.eat(TokenType.LPAREN)
            node = self.expr()
            self.eat(TokenType.RPAREN)
            return node
        elif token.type == TokenType.REGEX:
            self.eat(TokenType.REGEX)
            return Str(token)
        elif token.type in (TokenType.PLUS, TokenType.MINUS, TokenType.PERCENT, TokenType.NOT):
            self.eat(token.type)
            return UnaryOp(token, self.factor())
        elif token.type == TokenType.PRINT:
            self.eat(TokenType.PRINT)
            return Print(self.expr())
        elif token.type == TokenType.PRINTF:
            self.eat(TokenType.PRINTF)
            format_string = self.expr()
            
            args = []
            if self.current_token.type == TokenType.COMMA:
                self.eat(TokenType.COMMA)
                args.append(self.expr())
                
                while self.current_token.type == TokenType.COMMA:
                    self.eat(TokenType.COMMA)
                    args.append(self.expr())
            
            return Printf(format_string, args)
        elif token.type == TokenType.INPUT:
            self.eat(TokenType.INPUT)
            prompt = None
            if self.current_token.type == TokenType.STRING:
                prompt = self.factor()
            return Input(prompt)
        elif token.type == TokenType.SCANF:
            self.eat(TokenType.SCANF)
            format_string = None
            if self.current_token.type == TokenType.STRING:
                format_string = self.factor()
            
            vars = []
            if self.current_token.type == TokenType.IDENTIFIER:
                vars.append(Var(self.current_token))
                self.eat(TokenType.IDENTIFIER)
                
                while self.current_token.type == TokenType.COMMA:
                    self.eat(TokenType.COMMA)
                    if self.current_token.type != TokenType.IDENTIFIER:
                        self.error("Expected identifier after comma")
                    vars.append(Var(self.current_token))
                    self.eat(TokenType.IDENTIFIER)
            
            if not vars:
                self.error("Expected at least one variable for scanf")
            
            return Scanf(format_string, vars)
        elif token.type == TokenType.CONST:
            self.eat(TokenType.CONST)
            if self.current_token.type != TokenType.IDENTIFIER:
                self.error("Expected identifier after const")
            name = self.current_token
            self.eat(TokenType.IDENTIFIER)
            self.eat(TokenType.ASSIGN)
            value = self.expr()
            return ConstDecl(name, value)
        elif token.type == TokenType.SYS:
            self.eat(TokenType.SYS)
            return Sys(self.expr())
        elif token.type == TokenType.EVAL:
            self.eat(TokenType.EVAL)
            return Eval(self.expr())
        elif token.type == TokenType.END:
            self.eat(TokenType.END)
            return End()
        elif token.type == TokenType.NOP:
            self.eat(TokenType.NOP)
            return Nop()
        elif token.type == TokenType.EXIT:
            self.eat(TokenType.EXIT)
            code = None
            if self.current_token.type != TokenType.NEWLINE and self.current_token.type != TokenType.EOF:
                code = self.expr()
            return Exit(code)
        elif token.type == TokenType.COLOR:
            self.eat(TokenType.COLOR)
            return Color(self.expr())
        elif token.type == TokenType.CLS:
            self.eat(TokenType.CLS)
            return Cls()
        elif token.type == TokenType.WAIT:
            self.eat(TokenType.WAIT)
            return Wait(self.expr())
        else:
            self.error(f"Unexpected token: {token.type}")
    
    def term(self):
        node = self.factor()
        
        while self.current_token.type in (TokenType.MULTIPLY, TokenType.DIVIDE, TokenType.FLOOR_DIV, 
                                         TokenType.MODULO, TokenType.POWER, TokenType.DOT):
            token = self.current_token
            if token.type == TokenType.DOT:
                self.eat(TokenType.DOT)
                right = self.factor()
                node = BinOp(node, Token(TokenType.ADD, '+', token.line, token.column), right)
            else:
                self.eat(token.type)
                node = BinOp(node, token, self.factor())
        
        return node
    
    def compare(self):
        node = self.term()
        
        while self.current_token.type in (TokenType.EQUAL, TokenType.NOT_EQUAL, TokenType.GREATER,
                                         TokenType.LESS, TokenType.DIAMOND, TokenType.LESS_EQUAL,
                                         TokenType.GREATER_EQUAL, TokenType.STRICT_EQUAL,
                                         TokenType.STRICT_NOT_EQUAL, TokenType.IN, TokenType.NOT_IN,
                                         TokenType.IS, TokenType.NOT_IS, TokenType.MATCH, TokenType.NOT_MATCH):
            token = self.current_token
            self.eat(token.type)
            node = BinOp(node, token, self.term())
        
        return node
    
    def expr(self):
        if self.current_token.type == TokenType.CONST:
            self.eat(TokenType.CONST)
            if self.current_token.type != TokenType.IDENTIFIER:
                self.error("Expected identifier after const")
            name = self.current_token
            self.eat(TokenType.IDENTIFIER)
            self.eat(TokenType.ASSIGN)
            value = self.expr()
            return ConstDecl(name, value)
        
        node = self.compare()
        
        while self.current_token.type in (TokenType.ADD, TokenType.SUBTRACT, TokenType.AND,
                                         TokenType.OR, TokenType.XOR):
            token = self.current_token
            self.eat(token.type)
            node = BinOp(node, token, self.compare())
        
        if self.current_token.type in (TokenType.ASSIGN, TokenType.RIGHT_ARROW, TokenType.LEFT_ARROW, 
                                      TokenType.DOUBLE_RIGHT_ARROW, TokenType.DOUBLE_LEFT_ARROW):
            token = self.current_token
            self.eat(token.type)
            right = self.expr()
            node = Assign(node, token, right)
        
        return node
    
    def parse(self):
        while self.current_token.type == TokenType.NEWLINE:
            self.eat(TokenType.NEWLINE)
        
        if self.current_token.type == TokenType.EOF:
            return None
        
        return self.statement()

class Interpreter:
    def __init__(self):
        self.symbols: Dict[str, Tuple[str, Any]] = {}
        self.loop_stack = []
        
        # 内置常量
        self.symbols.update({
            'PI': ('const', math.pi),
            'PHI': ('const', (1 + math.sqrt(5)) / 2),
            'E': ('const', math.e)
        })

        # 内置函数（带参数支持）
        self.builtin_functions = {
            'sin': math.sin,
            'cos': math.cos,
            'tan': math.tan,
            'asin': math.asin,
            'acos': math.acos,
            'atan': math.atan,
            'log': math.log,
            'exp': math.exp,
            'sqrt': math.sqrt,
            'abs': abs,
            'path': lambda: os.getcwd(),  # 无参数函数
            'comp': lambda: os.path.abspath(__file__),  # 无参数函数
            'min': min,
            'max': max
        }
    
    def visit_BuiltinCall(self, node: BuiltinCall):
        func_name = node.func_name
        args = [self.visit(arg) for arg in node.args] if node.args else []
        
        if func_name not in self.builtin_functions:
            raise Exception(f"Undefined built-in function: {func_name}")
        
        func = self.builtin_functions[func_name]
        
        # 检查参数数量
        expected_arg_count = func.__code__.co_argcount
        if len(args) != expected_arg_count:
            raise Exception(f"{func_name} expects {expected_arg_count} arguments, got {len(args)}")
        
        return func(*args)
    
    def visit_SubDefinition(self, node: SubDefinition):
        sub_name = node.name.value
        # 检查是否已定义
        if sub_name in self.symbols:
            symbol_type, _ = self.symbols[sub_name]
            if symbol_type == 'const':
                raise Exception(f"Cannot redefine constant as subroutine: {sub_name}")
            elif symbol_type == 'var':
                raise Exception(f"Cannot redefine variable as subroutine: {sub_name}")
            else:
                raise Exception(f"Subroutine already defined: {sub_name}")
        
        # 存储子程序定义（无参数）
        self.symbols[sub_name] = ('sub', node)
        return None
    
    def visit(self, node: ASTNode):
        method_name = f'visit_{type(node).__name__}'
        method = getattr(self, method_name, self.generic_visit)
        return method(node)
    
    def generic_visit(self, node: ASTNode):
        raise Exception(f"No visit_{type(node).__name__} method")
    
    def visit_Block(self, node: Block):
        result = None
        for statement in node.statements:
            result = self.visit(statement)
        return result
    
    def visit_Num(self, node: Num):
        return node.value
    
    def visit_Str(self, node: Str):
        return node.value
    
    def visit_Bool(self, node: Bool):
        return node.value
    
    def visit_Nil(self, node: Nil):
        return node.value

    def visit_SubCall(self, node: SubCall):
        sub_name = node.token.value
        if sub_name not in self.symbols or self.symbols[sub_name][0] != 'sub':
            # Try to handle as variable
            if sub_name in self.symbols:
                _, value = self.symbols[sub_name]
                return value
            raise Exception(f"Undefined subroutine: {sub_name}")
        
        # Get subroutine definition and execute
        _, sub_def = self.symbols[sub_name]
        return self.visit(sub_def.body)

    def visit_Var(self, node):
        var_name = node.token.value
        if var_name in self.symbols:
            return self.symbols[var_name][1]
        raise Exception(f"Undefined variable: {var_name}")

    def builtin_path(self):  # ➡️ 文件路径函数（无参数）
        import os
        return os.getcwd()

    def builtin_comp(self):  # ➡️ 解释器路径函数（无参数）
        import os
        return os.path.abspath(__file__)
    
    def visit_Assign(self, node: Assign):
        # Handle left side (could be Var or SubCall)
        if isinstance(node.left, Var):
            var_name = node.left.token.value
        elif isinstance(node.left, SubCall):
            var_name = node.left.token.value
        else:
            raise Exception("Invalid assignment target")
        
        value = self.visit(node.right)
        
        # Check if it's a constant
        if var_name in self.symbols and self.symbols[var_name][0] == 'const':
            raise Exception(f"Cannot reassign constant: {var_name}")
        
        # Check if it's a subroutine
        if var_name in self.symbols and self.symbols[var_name][0] == 'sub':
            raise Exception(f"Cannot reassign subroutine: {var_name}")
        
        # Store or update
        self.symbols[var_name] = ('var', value)
        return value
    
    def visit_ConstDecl(self, node: ConstDecl):
        var_name = node.name.value
        # Check if already defined
        if var_name in self.symbols:
            raise Exception(f"Identifier already defined: {var_name}")
        
        value = self.visit(node.value)
        self.symbols[var_name] = ('const', value)
        return value
    
    def visit_SubDefinition(self, node: SubDefinition):
        sub_name = node.name.value
        # Check if already defined
        if sub_name in self.symbols:
            symbol_type, _ = self.symbols[sub_name]
            if symbol_type == 'const':
                raise Exception(f"Cannot redefine constant as subroutine: {sub_name}")
            elif symbol_type == 'var':
                raise Exception(f"Cannot redefine variable as subroutine: {sub_name}")
            else:
                raise Exception(f"Subroutine already defined: {sub_name}")
        
        # Store subroutine definition
        self.symbols[sub_name] = ('sub', node)
        return None
    
    def visit_BinOp(self, node: BinOp):
        left = self.visit(node.left)
        right = self.visit(node.right)
        
        if node.op.type == TokenType.ADD:
            if isinstance(left, str) or isinstance(right, str):
                return str(left) + str(right)
            return left + right
        elif node.op.type == TokenType.SUBTRACT:
            return left - right
        elif node.op.type == TokenType.MULTIPLY:
            if isinstance(left, str) and isinstance(right, (int, float)):
                return left * int(right)
            elif isinstance(right, str) and isinstance(left, (int, float)):
                return right * int(left)
            return left * right
        elif node.op.type == TokenType.DIVIDE:
            return left / right
        elif node.op.type == TokenType.FLOOR_DIV:
            return left // right
        elif node.op.type == TokenType.POWER:
            return left ** right
        elif node.op.type == TokenType.MODULO:
            return left % right
        elif node.op.type == TokenType.EQUAL:
            return left == right
        elif node.op.type == TokenType.NOT_EQUAL:
            return left != right
        elif node.op.type == TokenType.GREATER:
            return left > right
        elif node.op.type == TokenType.LESS:
            return left < right
        elif node.op.type == TokenType.DIAMOND:
            return left != right
        elif node.op.type == TokenType.LESS_EQUAL:
            return left <= right
        elif node.op.type == TokenType.GREATER_EQUAL:
            return left >= right
        elif node.op.type == TokenType.STRICT_EQUAL:
            return type(left) == type(right) and left == right
        elif node.op.type == TokenType.STRICT_NOT_EQUAL:
            return type(left) != type(right) or left != right
        elif node.op.type == TokenType.IN:
            try:
                return left in right
            except TypeError:
                raise Exception(f"Cannot check membership in {type(right)}")
        elif node.op.type == TokenType.NOT_IN:
            try:
                return left not in right
            except TypeError:
                raise Exception(f"Cannot check membership in {type(right)}")
        elif node.op.type == TokenType.IS:
            return left is right
        elif node.op.type == TokenType.NOT_IS:
            return left is not right
        elif node.op.type == TokenType.MATCH:
            if not isinstance(right, str):
                raise Exception("Right operand of =~ must be a regex string")
            return bool(re.search(right, str(left)))
        elif node.op.type == TokenType.NOT_MATCH:
            if not isinstance(right, str):
                raise Exception("Right operand of !~ must be a regex string")
            return not bool(re.search(right, str(left)))
        elif node.op.type == TokenType.AND:
            return left and right
        elif node.op.type == TokenType.OR:
            return left or right
        elif node.op.type == TokenType.XOR:
            return bool(left) != bool(right)
        else:
            raise Exception(f"Unknown operator: {node.op.type}")
    
    def visit_UnaryOp(self, node: UnaryOp):
        expr = self.visit(node.expr)
        
        if node.op.type == TokenType.PLUS:
            return abs(expr)
        elif node.op.type == TokenType.MINUS:
            return -expr
        elif node.op.type == TokenType.PERCENT:
            return expr / 100
        elif node.op.type == TokenType.NOT:
            return not expr
        else:
            raise Exception(f"Unknown unary operator: {node.op.type}")
    
    def visit_Print(self, node: Print):
        value = self.visit(node.expr)
        print(value)
        return value
    
    def visit_Printf(self, node: Printf):
        format_str = str(self.visit(node.format_string))
        values = [self.visit(arg) for arg in node.args]
        
        try:
            result = format_str % tuple(values) if values else format_str
            print(result, end='')
        except (TypeError, ValueError) as e:
            raise Exception(f"printf format error: {e}")
        
        return None
    
    def visit_Input(self, node: Input):
        prompt = self.visit(node.prompt) if node.prompt else None
        if prompt is not None:
            user_input = input(prompt)
        else:
            user_input = input()
        
        try:
            return float(user_input)
        except ValueError:
            if user_input.lower() == 'true':
                return True
            elif user_input.lower() == 'false':
                return False
            elif user_input.lower() == 'nil':
                return None
            return user_input
    
    def visit_Scanf(self, node: Scanf):
        format_str = self.visit(node.format_string) if node.format_string else ""
        if format_str:
            user_input = input(format_str)
        else:
            user_input = input()
        
        if ',' in user_input:
            values = [v.strip() for v in user_input.split(',')]
        else:
            values = user_input.split()
        
        if len(values) < len(node.vars):
            raise Exception(f"Not enough values provided (expected {len(node.vars)}, got {len(values)})")
        
        for i, var in enumerate(node.vars):
            var_name = var.token.value
            
            # Check if it's a constant
            if var_name in self.symbols and self.symbols[var_name][0] == 'const':
                raise Exception(f"Cannot reassign constant: {var_name}")
            
            # Check if it's a subroutine
            if var_name in self.symbols and self.symbols[var_name][0] == 'sub':
                raise Exception(f"Cannot reassign subroutine: {var_name}")
            
            try:
                value = float(values[i])
                if value.is_integer():
                    value = int(value)
            except ValueError:
                value = values[i]
            
            self.symbols[var_name] = ('var', value)
        
        return None
    
    def visit_Sys(self, node: Sys):
        import os
        command = str(self.visit(node.command))
        return os.system(command)
    
    def visit_Eval(self, node: Eval):
        code = str(self.visit(node.code))
        try:
            run_nova(code)
        except Exception as e:
            raise Exception(f"Eval error: {e}")
    
    def visit_End(self, node: End):
        import sys
        sys.exit(0)
    
    def visit_Nop(self, node: Nop):
        pass
    
    def visit_Exit(self, node: Exit):
        import sys
        code = self.visit(node.code) if node.code else 0
        sys.exit(code)
    
    def visit_Color(self, node: Color):
        color = str(self.visit(node.color)).lower()
        try:
            import os
            if os.name == 'nt':
                import ctypes
                colors = {
                    'black': 0,
                    'blue': 1,
                    'green': 2,
                    'aqua': 3,
                    'red': 4,
                    'purple': 5,
                    'yellow': 6,
                    'white': 7,
                    'gray': 8,
                    'lightblue': 9,
                    'lightgreen': 10,
                    'lightaqua': 11,
                    'lightred': 12,
                    'lightpurple': 13,
                    'lightyellow': 14,
                    'brightwhite': 15,
                    'reset': 7
                }
                color_code = colors.get(color, 7)
                ctypes.windll.kernel32.SetConsoleTextAttribute(ctypes.windll.kernel32.GetStdHandle(-11), color_code)
            else:
                colors = {
                    'black': '\033[30m',
                    'red': '\033[31m',
                    'green': '\033[32m',
                    'yellow': '\033[33m',
                    'blue': '\033[34m',
                    'purple': '\033[35m',
                    'aqua': '\033[36m',
                    'white': '\033[37m',
                    'gray': '\033[90m',
                    'lightred': '\033[91m',
                    'lightgreen': '\033[92m',
                    'lightyellow': '\033[93m',
                    'lightblue': '\033[94m',
                    'lightpurple': '\033[95m',
                    'lightaqua': '\033[96m',
                    'brightwhite': '\033[97m',
                    'reset': '\033[0m'
                }
                print(colors.get(color, '\033[0m'), end='')
        except:
            pass
    
    def visit_Cls(self, node: Cls):
        import os
        os.system('cls' if os.name == 'nt' else 'clear')
        
    def visit_Wait(self, node: Wait):
        import time
        seconds = self.visit(node.seconds)
        time.sleep(seconds)
        return seconds
    
    def visit_If(self, node: If):
        condition = self.visit(node.condition)
        
        if condition:
            return self.visit(node.then_branch)
        
        for elif_condition, elif_branch in node.elif_branches:
            if self.visit(elif_condition):
                return self.visit(elif_branch)
        
        if node.else_branch is not None:
            return self.visit(node.else_branch)
        
        return None
    
    def visit_Unless(self, node: Unless):
        condition = self.visit(node.condition)
        
        if not condition:
            return self.visit(node.then_branch)
        
        if node.else_branch is not None:
            return self.visit(node.else_branch)
        
        return None
    
    def visit_While(self, node: While):
        self.loop_stack.append('while')
        try:
            while self.visit(node.condition):
                try:
                    self.visit(node.body)
                except ContinueSignal:
                    continue
                except BreakSignal:
                    break
        finally:
            self.loop_stack.pop()
        return None
    
    def visit_Until(self, node: Until):
        self.loop_stack.append('until')
        try:
            while not self.visit(node.condition):
                try:
                    self.visit(node.body)
                except ContinueSignal:
                    continue
                except BreakSignal:
                    break
        finally:
            self.loop_stack.pop()
        return None
        
    def visit_DoWhile(self, node: DoWhile):
        self.loop_stack.append('do-while')
        try:
            while True:
                try:
                    self.visit(node.body)
                except ContinueSignal:
                    continue
                except BreakSignal:
                    break
                
                if not self.visit(node.condition):
                    break
        finally:
            self.loop_stack.pop()
        return None
        
    def visit_DoUntil(self, node: DoUntil):
        self.loop_stack.append('do-until')
        try:
            while True:
                try:
                    self.visit(node.body)
                except ContinueSignal:
                    continue
                except BreakSignal:
                    break
                
                if self.visit(node.condition):
                    break
        finally:
            self.loop_stack.pop()
        return None
    
    def visit_Loop(self, node: Loop):
        self.loop_stack.append('loop')
        try:
            while True:
                try:
                    self.visit(node.body)
                except ContinueSignal:
                    continue
                except BreakSignal:
                    break
        finally:
            self.loop_stack.pop()
        return None
    
    def visit_Rep(self, node: Rep):
        count = int(self.visit(node.count))
        self.loop_stack.append('rep')
        try:
            for _ in range(count):
                try:
                    self.visit(node.body)
                except ContinueSignal:
                    continue
                except BreakSignal:
                    break
        finally:
            self.loop_stack.pop()
        return None
    
    def visit_Match(self, node: Match):
        value = self.visit(node.expr)
        
        for case in node.cases:
            if case.pattern is None:  # _ wildcard
                return self.visit(case.body)
            
            pattern_value = self.visit(case.pattern)
            if value == pattern_value:
                return self.visit(case.body)
        
        return None
    
    def visit_When(self, node: When):
        expr_value = self.visit(node.expr) if node.expr is not None else None
        
        for case in node.cases:
            condition_value = self.visit(case.condition)
            
            if (node.expr is not None and expr_value == condition_value) or \
               (node.expr is None and bool(condition_value)):
                return self.visit(case.body)
        
        if node.else_case is not None:
            return self.visit(node.else_case)
        
        return None
    def visit_ForIn(self, node: ForIn):
        iterable = self.visit(node.iterable)
        var_name = node.var.value
        
        if not isinstance(iterable, (list, tuple, str, range)):
            raise Exception(f"Cannot iterate over {type(iterable)}")
        
        self.loop_stack.append('for-in')
        try:
            for item in iterable:
                # Store current item in variable
                self.symbols[var_name] = ('var', item)
                
                try:
                    self.visit(node.body)
                except ContinueSignal:
                    continue
                except BreakSignal:
                    break
        finally:
            self.loop_stack.pop()
        return None

    def visit_ForRange(self, node: ForRange):
        self.loop_stack.append('for-range')
        try:
            # Execute initialization if present
            if node.init:
                self.visit(node.init)
            
            while True:
                # Check condition if present
                if node.condition:
                    if not self.visit(node.condition):
                        break
                
                try:
                    self.visit(node.body)
                except ContinueSignal:
                    pass  # Still execute update
                except BreakSignal:
                    break
                
                # Execute update if present
                if node.update:
                    self.visit(node.update)
        finally:
            self.loop_stack.pop()
        return None

    def visit_Try(self, node:Try):
        try:
            self.visit(node.try_branch)
        except:
            if node.except_branch:
                self.visit(node.except_branch)
        finally:
            if node.finally_branch:
                self.visit(node.finally_branch)

    def visit_Break(self, node: Break):
        if not self.loop_stack:
            raise Exception("Break statement outside loop")
        raise BreakSignal()
    
    def visit_Continue(self, node: Continue):
        if not self.loop_stack:
            raise Exception("Continue statement outside loop")
        raise ContinueSignal()
    
    def visit_BuiltinCall(self, node: BuiltinCall):
        func_name = node.func_name
        args = [self.visit(arg) for arg in node.args] if node.args else []
        
        if func_name not in self.builtin_functions:
            raise Exception(f"Undefined built-in function: {func_name}")
        
        func = self.builtin_functions[func_name]
        
        # 检查参数数量
        expected_arg_count = func.__code__.co_argcount
        if len(args) != expected_arg_count:
            raise Exception(f"{func_name} expects {expected_arg_count} arguments, got {len(args)}")
        
        return func(*args)

class BreakSignal(Exception):
    pass

class ContinueSignal(Exception):
    pass

def run_nova(code: str):
    lexer = Lexer(code)
    parser = Parser(lexer)
    interpreter = Interpreter()
    
    try:
        while True:
            node = parser.parse()
            if node is None:
                break
            interpreter.visit(node)
            if parser.current_token.type == TokenType.EOF:
                break
    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    if len(sys.argv) > 1:
        try:
            with open(sys.argv[1], 'r', encoding='utf-8') as file:
                run_nova(file.read())
        except Exception as e:
            print(f"Error reading file: {e}")
            sys.exit(1)
    else:
        code = """
for a in "123123123":
    print a
"""
        run_nova(code)